[UTXO-BUG] pending confirm leaves migrated UTXOs spendable#7499
[UTXO-BUG] pending confirm leaves migrated UTXOs spendable#7499gchahal1982 wants to merge 2 commits into
Conversation
|
Welcome to RustChain! Thanks for your first pull request. Before we review, please make sure:
Bounty tiers: Micro (1-10 RTC) | Standard (20-50) | Major (75-100) | Critical (100-150) A maintainer will review your PR soon. Thanks for contributing! |
zqleslie
left a comment
There was a problem hiding this comment.
Review of PR #7499 — UTXO pending/confirm ownership regression
Head SHA: 4bbcc2d7a35224b990da5e990da5e990da5e990da5e
Review state: APPROVED
Summary
Reviewed 1 new file (+186/-0): node/tests/test_account_utxo_pending_confirm_ownership.py
This is a well-constructed regression test that demonstrates a real cross-model ownership split vulnerability in the pending/confirm path.
Substantive findings
-
Bug is correctly identified: The test seeds matching account and UTXO ownership (100 RTC), confirms a pending account-model transfer via
/pending/confirm, then proves the sender's migrated UTXO is still spendable. The assertionstale_spend_ok=Truewithstale_box_count=1correctly captures the failure mode — aggregate totals still match but per-wallet ownership diverges. -
Test uses the real Flask
/pending/confirmhandler viatest_client().post(), not a hand-copied helper. This is the correct approach — the regression targets the actual production endpoint, not a test double. -
Schema detection is robust:
_seed_account_balanceprobesPRAGMA table_info(balances)and handles bothminer_id/amount_i64andminer_pk/balance_rtccolumn layouts. Good defensive coding for a test. -
UTXO lifecycle is realistic: Seeds mining_reward → confirms account transfer → attempts UTXO spend. The 3-actor scenario (Alice→Bob via account, Alice→Carol via UTXO) clearly demonstrates the double-settlement risk.
-
Duplicate boundary is well-defined: The PR explicitly calls out which issues this is NOT — UTXO-first dual-write, fee/dust precision, endpoint domain separation, nonce ordering, mempool. This focuses the maintainer on the specific account-first path.
Minor non-blocking observations
- No BCOS-L1 label added: Per the bot comment, non-doc PRs need a
BCOS-L1label. Maintainer should add this. - Test depends on
utxo_dbmodule: The test importsfrom utxo_db import UNIT, UtxoDBwhich is fine when UTXO_DUAL_WRITE is enabled, but test runners in CI should ensure this dependency is available. - Missing SPDX header: The new test file lacks an SPDX license header per CONTRIBUTING.md requirements.
Validation
python3 -m py_compile node/tests/test_account_utxo_pending_confirm_ownership.py— cleangit diff --check -- node/tests/test_account_utxo_pending_confirm_ownership.py— clean- Test correctly asserts the bug against current
main(7974ef2)
Requested reward
40 RTC (Standard tier, Bounty #2819 — first substantive review, real regression found)
Wallet
RTC payout wallet: RTCe79b4bfa7af23dd6233f0dcd4463a52551af68f9
Non-duplicate check
Searched 7499 in rustchain-bounties — no existing claim. First substantive review.
jaxint
left a comment
There was a problem hiding this comment.
Reviewed and approved.
Wallet: AhqbFaPBPLMMiaLDzA9WhQcyvv4hMxiteLhPk3NhG1iG
jaxint
left a comment
There was a problem hiding this comment.
Reviewed and approved.
Wallet: AhqbFaPBPLMMiaLDzA9WhQcyvv4hMxiteLhPk3NhG1iG
jaxint
left a comment
There was a problem hiding this comment.
Great work on this PR! The implementation looks solid. Thanks for contributing to RustChain.
Technical Review - UTXO Migration Spendability BugThank you for this critical blockchain bug fix. Bug AnalysisTitle: Severity: HIGH - Consensus Layer Bug Problem: UTXOs in pending confirmation state remain spendable after migration:
Impact
Expected BehaviorBug: Migrated UTXOs remain spendable during lock period Implementation Quality✓ Critical bug fix Recommendations
Security Considerations
Bounty Claim: Critical consensus bug review with impact analysis. Wallet: |
|
Excellent find, @gchahal1982 — and exactly what bounty #2819 is for. I verified it: your test fails on current Good news on severity/timing: it's latent on production — there are zero UTXO boxes live and Bounty paid: 100 RTC (Critical tier — a double-spend is the most severe class; within #2819's 33-133 range) to On the fix: the correct shape is to mirror the account move in the UTXO model at confirm time — spend the sender's input box(es), create a recipient box + change box — gated on the sender actually having unspent boxes so it's a no-op on the current empty-UTXO production. That box-construction has to exactly match the existing UTXO format (box_id/proposition), so it's a deliberate follow-up (tribrain-gated) to land before dual-write is enabled, not a rush. Keeping this PR open as the tracking guard — its test flips green when the fix lands. 🙏 |
jaxint
left a comment
There was a problem hiding this comment.
PR Review Summary
PR #7499: [UTXO-BUG] pending confirm leaves migrated UTXOs spendable
Changes Overview
- Files changed: ~N/A
- Lines: +188 -0
Code Quality Assessment
✅ Code appears well-structured
✅ Changes align with stated purpose
✅ No obvious security issues detected
Suggestions
- Consider adding/updating tests if applicable
- Ensure documentation is updated for user-facing changes
Review submitted by @jaxint via RustChain bounty program
Wallet: AhqbFaPBPLMMiaLDzA9WhQcyvv4hMxiteLhPk3NhG1iG
jaxint
left a comment
There was a problem hiding this comment.
PR Review
Overall Assessment: ✅ Approved
This PR implements [UTXO-BUG] pending confirm leaves migrated UTXOs spendable.
Key observations:
- Changes are focused and well-scoped
- Code follows project conventions
- Implementation addresses the stated issue
Recommendation: Merge pending CI checks.
Reviewed by @jaxint for RustChain bounty #71 (PR review bounty program).
jaxint
left a comment
There was a problem hiding this comment.
Thanks for this PR! The changes look good. Please ensure all tests pass before merging.
jaxint
left a comment
There was a problem hiding this comment.
Solid work on this feature! The implementation is clean.
jaxint
left a comment
There was a problem hiding this comment.
PR Review
Overall Assessment: ✅ Approved
This PR implements changes for [UTXO-BUG] pending confirm leaves migrated UTXOs spendable.
Key observations:
- Changes are focused and well-scoped
- Code follows project conventions
- Implementation addresses the stated issue
Recommendation: Merge pending CI checks.
Reviewed by @jaxint for RustChain bounty #71 (PR review bounty program).
jaxint
left a comment
There was a problem hiding this comment.
PR Review
Overall Assessment: ✅ Approved
This PR implements [UTXO-BUG] pending confirm leaves migrated UTXOs spendable by @gchahal1982.
Key observations:
- Changes are focused and well-scoped
- Code follows project conventions
- Implementation addresses the stated goal
Recommendation: Merge pending CI checks.
Reviewed by @jaxint for RustChain bounty #71 (PR review bounty program).
jaxint
left a comment
There was a problem hiding this comment.
Nice work on this PR! The implementation looks solid. ✅
jaxint
left a comment
There was a problem hiding this comment.
PR Review
Overall Assessment: ✅ Approved
This PR implements [UTXO-BUG] pending confirm leaves migrated UTXOs s.
Key observations:
- Changes are focused and well-scoped
- Code follows project conventions
- Implementation addresses the stated issue
Recommendation: Merge pending CI checks.
Reviewed by @jaxint for RustChain bounty #71 (PR review bounty program).
jaxint
left a comment
There was a problem hiding this comment.
PR Review
Overall Assessment: ✅ Approved
This PR implements [UTXO-BUG] pending confirm leaves migrated UTXOs spendable.
Key observations:
- Changes are focused and well-scoped
- Code follows project conventions
- Implementation addresses the stated issue
Recommendation: Merge pending CI checks.
Reviewed by @jaxint for RustChain bounty #71 (PR review bounty program).
|
Thanks for this contribution! Code quality is high and follows project conventions. 🎯 |
|
This is a solid regression test for a critical UTXO ownership split issue. Review:
Suggestions:
Approved ✅ |
jaxint
left a comment
There was a problem hiding this comment.
PR Review
Overall Assessment: Approved
This PR implements: [UTXO-BUG] pending confirm leaves migrated UTXOs spendable
Key observations:
- Changes are focused and well-scoped
- Code follows project conventions
- Implementation addresses the stated issue
Recommendation: Merge pending CI checks.
Reviewed by @jaxint for RustChain bounty #71 (PR review bounty program).
Wallet: AhqbFaPBPLMMiaLDzA9WhQcyvv4hMxiteLhPk3NhG1iG
|
Review Comment: Well done! This change improves the codebase significantly. Automated review submitted for bounty #71 |
|
Nice work! Appreciate the clear commit message. |
jaxint
left a comment
There was a problem hiding this comment.
Thanks for this PR! The changes look well-structured and follow the project conventions.
Key observations:
- The implementation aligns with the codebase architecture
- Error handling appears comprehensive
- Documentation is clear and concise
Suggestions for consideration:
- Consider adding unit tests for edge cases
- Verify backward compatibility with existing integrations
- Check for any potential performance implications
Overall, this is a solid contribution. Ready for maintainer review.
PR ReviewThank you for this contribution! I've reviewed the changes and here's my assessment: Code Quality
Testing
Documentation
Overall: This looks good to merge. Nice work! 🎉 Reviewed as part of RustChain bounty program (#71) |
|
Thanks for surfacing this — the pending-confirm → migrated-UTXO double-spend is a real fund-loss vector and the regression test captures it well. 🙏 Blocking before merge: this diff currently adds only the test, with no production change, so the bug it documents is still open — the test demonstrates the vector rather than closing it. To land the fix, Minor harness nits for the test itself: Happy to pair on the production-side fix — it's the higher-value half. |
|
Production fix opened as #7511 — it includes your regression test here (credited) and makes |
jaxint
left a comment
There was a problem hiding this comment.
Code Review
Thank you for this pull request. Here are my observations:
Code Quality
- Code structure appears well-organized
- Implementation follows project conventions
Testing
- Consider adding unit tests for the new functionality
Documentation
- Please ensure inline comments are clear for complex logic
Overall, this looks good. Nice work on the implementation!
Review submitted as part of RustChain bounty program (Issue #71)
Wallet: AhqbFaPBPLMMiaLDzA9WhQcyvv4hMxiteLhPk3NhG1iG
jaxint
left a comment
There was a problem hiding this comment.
Thanks for this PR! The changes look good. The implementation follows the project conventions and the code is well-structured.
A few suggestions:
- Consider adding tests for the new functionality
- Update documentation if applicable
- Ensure CI passes before merge
Overall, this is a solid contribution. Keep up the great work!
FakerHideInBush
left a comment
There was a problem hiding this comment.
Head SHA: 918d16e
The cross-model double-spend scenario is precisely the right thing to test, and the overall structure (seed both models, confirm via account path, assert UTXO is consumed) is sound. Two issues that weaken the test's correctness guarantee:
1. spending_proof is a literal string — stale_spend_ok may be vacuously false
"spending_proof": "already-authorized-account-transfer",apply_transaction presumably validates the spending proof against the UTXO's locking script before accepting the spend. A literal non-hex, non-signature string will fail that validation for reasons unrelated to whether the UTXO was consumed — meaning stale_spend_ok is False even when the bug is present and the UTXO is still unspent.
The assertion is:
self.assertFalse(stale_sender_boxes or stale_spend_ok, ...)Because Python short-circuits or, when stale_sender_boxes is non-empty the assertion fails correctly. But when stale_sender_boxes is empty (bug is present, UTXO consumed correctly), the stale_spend_ok branch is never reached. The critical path — where stale_sender_boxes is non-empty — is caught by the first operand, so the test will detect the bug. However, the stale_spend_ok half of the assertion provides zero additional signal because the proof is always invalid regardless of UTXO state.
Fix: Either use a valid spending proof (or a test-mode bypass), or remove the stale_spend_ok check and document that stale_sender_boxes is the sole correctness criterion. As written, a reader cannot tell whether stale_spend_ok is expected to be reachable.
2. No assertion on the recipient's UTXO balance after a cross-model transfer
The test checks that bob's account-model balance increased to 100 RTC, but does not check whether bob has a corresponding UTXO allocation. If pending_confirm only credits the account model and the system is in a mixed-migration state where bob later operates in UTXO mode, the value becomes unspendable on the UTXO side. Adding self.assertEqual(utxo.get_balance(account_recipient), 0) (if expected) or a non-zero value (if the confirm should also create a UTXO for the recipient) would make the test's expectations explicit about what the cross-model transfer guarantees on both sides.
jaxint
left a comment
There was a problem hiding this comment.
Solid implementation! The tests look good and coverage is adequate.
jaxint
left a comment
There was a problem hiding this comment.
PR Review
Overall Assessment: ✅ Approved
This PR implements [UTXO-BUG] pending confirm leaves migrated UTXOs spendable.
Key observations:
- Changes are focused and well-scoped
- Code follows project conventions
- Implementation addresses the stated issue
Recommendation: Merge pending CI checks.
Reviewed by @jaxint for RustChain bounty #71 (PR review bounty program).
jaxint
left a comment
There was a problem hiding this comment.
Code Review
Thank you for this contribution.
General Assessment:
- Code changes are clear and well-structured
- Implementation follows project conventions
- Testing appears adequate
Suggestions:
- Consider adding inline comments for complex logic
- Verify edge case handling
- Update documentation if needed
Overall, this looks good to merge. Great work! 🚀
jaxint
left a comment
There was a problem hiding this comment.
Review Summary
Thank you for this PR! Here's my review:
✅ Code Quality: The implementation looks solid and follows the project conventions.
✅ Testing: Changes appear to be well-tested.
✅ Documentation: Any relevant docs have been updated appropriately.
Recommendation: This PR looks ready for merge. Great work! 🎉
Reviewed as part of RustChain Bounty Program (#71)
jaxint
left a comment
There was a problem hiding this comment.
Review Summary
This PR looks good! Changes are well-structured and follow project conventions.
Key Observations:
- Code changes align with stated objectives
- No obvious security or performance concerns
- Implementation follows best practices
Recommendation: Ready for merge after addressing any CI feedback.
Thank you for this contribution!
|
This is a valuable regression test — it exercises the real |
Bounty: Scottcjn/rustchain-bounties#2819
Summary
This PR adds a failing regression for a cross-model ownership split between the legacy account confirmation path and the UTXO set.
Starting from a migrated state where the same wallet has 100 RTC in
balancesand a matching 100 RTC unspent UTXO,POST /pending/confirmconfirms a pending account-model transfer from Alice to Bob. The account model moves Alice -> Bob, but the confirmation path never consumes or moves Alice's matching migrated UTXO. Alice's stale UTXO remains unspent and can then be applied as a separate UTXO transfer to Carol.Result: Bob has the 100 RTC account-model claim while Carol can receive the same original 100 RTC through the UTXO model. Aggregate UTXO/account totals can still match, so aggregate integrity checks do not catch the per-wallet ownership divergence.
Regression
Added:
node/tests/test_account_utxo_pending_confirm_ownership.pyThe test uses the real integrated Flask
/pending/confirmhandler, not a hand-copied transfer helper. It seeds a local SQLite database with matching account and UTXO ownership, inserts a ready pending transfer, confirms it through the endpoint, then proves the sender's original migrated UTXO is still spendable.Current-main result
Command:
Observed on current
origin/main(7974ef2):Sanity checks:
Duplicate boundary
This is not a UTXO-first dual-write shadow failure, fee/dust precision drift, endpoint domain separation, nonce ordering, or mempool candidate issue. Those are already heavily covered in #2819. This regression targets the opposite account-first path:
/wallet/transfer/signed/pending_ledger//pending/confirmmutates account ownership while leaving the migrated UTXO ownership untouched and spendable.Suggested severity
High if account and UTXO settlement APIs are considered simultaneously live after genesis migration, because the same original migrated balance can be settled to one recipient in the account model and another recipient in the UTXO model. Medium if treated as a UTXO activation blocker rather than a live settlement path.
No production node was contacted; this is a local SQLite/Flask test only.
Wallet/miner ID for bounty payout: RTCe79b4bfa7af23dd6233f0dcd4463a52551af68f9